﻿using CacheManager;
using Castle.DynamicProxy;
using System.Linq;
using System.Reflection;

namespace CacheAOP_Castle.AOPCache
{
    public class CachingInterceptor : IInterceptor
    {
        private ICacheManager _cacheProvider;
        public CachingInterceptor(ICacheManager cacheProvider)
        {
            _cacheProvider = cacheProvider;
        }

        /// <summary>
        /// Intercept the specified invocation.
        /// </summary>
        /// <returns>The intercept.</returns>
        /// <param name="invocation">Invocation.</param>
        public void Intercept(IInvocation invocation)
        {
            var qCachingAttribute = this.GetCachingAttributeInfo(invocation.MethodInvocationTarget ?? invocation.Method);
            if (qCachingAttribute != null)
            {
                ProceedCaching(invocation, qCachingAttribute);
            }
            else
            {
                invocation.Proceed();
            }
        }

        /// <summary>
        /// Gets the QCaching attribute info.
        /// </summary>
        /// <returns>The QC aching attribute info.</returns>
        /// <param name="method">Method.</param>
        private RedisCacheAttribute GetCachingAttributeInfo(MethodInfo method)
        {
            return method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(RedisCacheAttribute)) as RedisCacheAttribute;
        }

        /// <summary>
        /// Proceeds the caching.
        /// </summary>
        /// <param name="invocation">Invocation.</param>
        /// <param name="attribute">Attribute.</param>
        private void ProceedCaching(IInvocation invocation, RedisCacheAttribute attribute)
        {
            var cacheKey = attribute.CacheKey;

            var cacheValue = _cacheProvider.Get(cacheKey);
            if (cacheValue != null)
            {
                invocation.ReturnValue = cacheValue;
                return;
            }

            invocation.Proceed();

            if (!string.IsNullOrWhiteSpace(cacheKey))
            {
                _cacheProvider.Set(cacheKey, invocation.ReturnValue, attribute.Expiration);
            }
        }
    }
}
